package com.example.csetpp.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.csetpp.exception.*;
import com.example.csetpp.mapper.ProblemMapper;
import com.example.csetpp.pojo.dto.PageUserDTO;
import com.example.csetpp.pojo.dto.user.*;
import com.example.csetpp.pojo.dto.messagequeue.MailMessage;
import com.example.csetpp.pojo.entity.User;
import com.example.csetpp.mapper.UserMapper;
import com.example.csetpp.pojo.vo.UserLoginVO;
import com.example.csetpp.pojo.vo.UserSearchVO;
import com.example.csetpp.service.UserService;
import com.example.csetpp.utils.HttpClientUtil;
import com.example.csetpp.utils.SnowFlakeID;
import com.example.csetpp.utils.EmailValidator;
import com.example.csetpp.utils.UserIdHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.example.csetpp.constants.MessageConstant.*;
import static com.example.csetpp.constants.RabbitMqConstant.MAIL_EXCHANGE;
import static com.example.csetpp.constants.RabbitMqConstant.MAIL_QUEUE_KEY;
import static com.example.csetpp.constants.RedisConstant.MAIL_CODE_KEY;
import static com.example.csetpp.constants.WeChatConstant.*;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private JavaMailSender sender;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ProblemMapper feedBackMapper;


    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account",userLoginDTO.getAccount()).or().eq("email",userLoginDTO.getAccount());
        User user = userMapper.selectOne(queryWrapper);
        userLoginDTO.setPassword(SaSecureUtil.md5(userLoginDTO.getPassword()));
        validateUserCredentials(user, userLoginDTO.getPassword());
        UserLoginVO userLoginVO = new UserLoginVO();
        BeanUtil.copyProperties(user,userLoginVO);
        return userLoginVO;
    }

//    @Override
//    public UserLoginVO loginInEmail(UserLoginInEmailDTO userLoginInEmailDTO) {
//        // 验证邮箱验证码
//
//        userLoginInEmailDTO.setPassword(SaSecureUtil.md5(userLoginInEmailDTO.getPassword()));
//        // 根据邮箱查询用户
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("email", userLoginInEmailDTO.getEmail()).eq("password",userLoginInEmailDTO.getPassword());
//        User user = userMapper.selectOne(queryWrapper);
//
//        // 检查用户是否存在
//        if (user == null) {
//            throw new UnregisteredException(WRONG_PASSWORD);
//        }
//
//        // 返回用户登录信息
//        return UserLoginVO.builder()
//                .id(user.getId())
//                .password(user.getPassword())
//                .email(user.getEmail())
//                .account(user.getAccount())
//                .build();
//    }



    @Override
    public UserLoginVO loginWithLocalPhone(UserLoginWithLocalPhone userLoginWithLocalPhone) {
//        String accessToken = getAccessToken();
//        String localPhone = getLocalNumber(userLoginWithLocalPhone.getCode(), accessToken);
//        User user = getUser(localPhone);
//        if(user == null)
//        {
//            throw new UnregisteredException(UNREGISTERED_MESSAGE);
//        }
//        return User.builder()
//                .password(user.getPassword())
//                .phone(user.getPhone())
//                .build();
        return null;
    }

    @Override
    public UserLoginVO register(User userDTO) {
        User user = getUser(userDTO.getEmail(),userDTO.getAccount());
        if(user != null)
        {
            throw new HadRegisteredException(HAD_REGISTERED);
        }
        user = User.builder()
                .id(SnowFlakeID.getSnowflakeId())
                .password(SaSecureUtil.md5(userDTO.getPassword()))
                .userName(userDTO.getUserName())
                .email(userDTO.getEmail())
                .account(userDTO.getAccount())
                .role(userDTO.getRole())
                .frozen(0)
                .createTime(System.currentTimeMillis())
                .build();
        userMapper.insert(user);
        UserLoginVO userLoginVO = new UserLoginVO();
        BeanUtil.copyProperties(user,userLoginVO);
        return userLoginVO;
    }
    @Override
    public String update(UserEditDTO userEditDTO) {
        User user ;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if(userEditDTO.getId() != null){
            user = getUserByID(userEditDTO.getId());
            queryWrapper.clear();
            queryWrapper.eq("account",userEditDTO.getAccount()).ne("id",user.getId()).or().eq("email",userEditDTO.getEmail());
            Long l = userMapper.selectCount(queryWrapper);
            if(l > 0){
                throw new UnregisteredException("账号或邮箱名重复!");
            }
        } else {
            queryWrapper.eq("account",userEditDTO.getAccount()).or().eq("email",userEditDTO.getEmail());
            user = userMapper.selectOne(queryWrapper);
        }
        if (user == null) {
            throw new UnregisteredException(UNREGISTERED_MESSAGE);
        }
        String id = user.getId();
        BeanUtil.copyProperties(userEditDTO,user);
        user.setId(id);
        if(userEditDTO.getPassword() != null){
            user.setPassword(SaSecureUtil.md5(userEditDTO.getPassword()));
        }
        userMapper.updateById(user);
        return "OK";
    }

    @Override
    public String delete(String id) {
        User user = userMapper.selectById(id);
        if (user == null) {
            throw new UnregisteredException(UNREGISTERED_MESSAGE);
        }
        int count = userMapper.deleteById(id);
        if(count == 0){
            throw new DeleteFailedException(USER_DELETE_WRONG);
        }
        return "OK";
    }

    //异步发送邮件，将邮件发给消息队列，监听者再进行邮件发送功能
    @Override
    public void senMailCode(String mail) {
        if (!EmailValidator.isValidEmail(mail)) {
            throw new EmailFormatError("邮箱格式不正确");
        }
        String redisCode = stringRedisTemplate.opsForValue().get(MAIL_CODE_KEY + mail);
        if(redisCode != null){
            throw new LoginFailedException("相同邮箱发送请求间隔少于1分钟！");
        }
        
        String code = RandomUtil.randomNumbers(4);

        //发送邮件给消息队列
        MailMessage mailMessage = new MailMessage(mail, code);
        rabbitTemplate.convertAndSend(MAIL_EXCHANGE, MAIL_QUEUE_KEY, mailMessage);

        //将邮件信息存入redis，有效期5分钟
        stringRedisTemplate.opsForValue().set(MAIL_CODE_KEY + mail, code, 1L, TimeUnit.MINUTES);
        log.info("发送邮件成功" + code);
    }

    //验证验证码功能
    @Override
    public boolean verifyCode(String code, String mail) {
        if(code == null || code.isBlank()){
            throw new LoginFailedException(VERIFY_CODE_ERROR);
        }
        String redisCode = stringRedisTemplate.opsForValue().get(MAIL_CODE_KEY + mail);
        if(redisCode == null || !redisCode.equals(code)){
            throw new LoginFailedException(VERIFY_CODE_ERROR);
        }

        return true;
    }

    @Override
    public UserProfile getProfile() {

        Long currentId = UserIdHolder.getCurrentId();
        User user = getUserByID(String.valueOf(currentId));
        user.setPassword(null);
        UserProfile userProfile = new UserProfile();
        BeanUtils.copyProperties(user, userProfile);
        return userProfile;
    }

    @Override
    public String changePassword(UserChangePasswordDTO userChangePasswordDTO) {
        String character = userChangePasswordDTO.getCharacter();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account",character).or().eq("email",character);
        User user = userMapper.selectOne(queryWrapper);
        if(user == null){
            throw new UnregisteredException(UNREGISTERED_MESSAGE);
        }
        user.setPassword(SaSecureUtil.md5(userChangePasswordDTO.getPassword()));
        userMapper.updateById(user);
        return "OK";
    }

    @Override
    public Object getPageUserList(PageUserDTO pageUserDTO) {
        Page<User> page = new Page<>(pageUserDTO.getPage(),pageUserDTO.getSize());
        QueryWrapper<User> queryWrapper =new QueryWrapper<>();
        page = userMapper.selectPage(page,queryWrapper);
        return page.getRecords();
    }

    @Override
    public Object searchUser(UserSearchDTO userSearchDTO) {
        Page<User> page = new Page<>(userSearchDTO.getPage(),userSearchDTO.getSize());
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(userSearchDTO.getUserName() !=null ,"user_name" ,userSearchDTO.getUserName())
                .eq(userSearchDTO.getRole() !=null ,"role" ,userSearchDTO.getRole())
                .eq(userSearchDTO.getFrozen() !=null ,"frozen" ,userSearchDTO.getFrozen())
                .like(userSearchDTO.getEmail() !=null ,"email" ,userSearchDTO.getEmail())
                .ge(userSearchDTO.getStartDate() !=null ,"create_time" ,userSearchDTO.getStartDate())
                .le(userSearchDTO.getEndDate() !=null ,"create_time" ,userSearchDTO.getEndDate());
        queryWrapper.orderByDesc("create_time");
        Long count = userMapper.selectCount(queryWrapper);

        page = userMapper.selectPage(page,queryWrapper);
        for(User user : page.getRecords()){
            user.setPassword(null);
        }
        return new UserSearchVO(count,page.getRecords());
    }


    //判断数据库中是否存在用户及用户密码是否正确
    private void validateUserCredentials(User user, String inputPassword) {
        if (user == null) {
            throw new UnregisteredException(UNREGISTERED_MESSAGE);
        }
        if (!Objects.equals(user.getPassword(), inputPassword)) {
            throw new WrongPasswordException(WRONG_PASSWORD);
        }
    }



    private User getUser(String email,String account)
    {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email).or().eq("account",account);
        return userMapper.selectOne(queryWrapper);
    }


    private User getUserByID(String id)
    {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        return userMapper.selectOne(queryWrapper);
    }


    private String getOpenId(String code)
    {
        Map<String, String> map = new HashMap<>();
        map.put("appid", WX_APP_ID);
        map.put("secret", WX_APP_SECRET);
        map.put("js_code", code);
        map.put("grant_type", WX_LOGIN_GRANT_TYPE);
        String json = HttpClientUtil.doGet(WX_LOGIN_URL, map);

        JSONObject jsonObject = JSON.parseObject(json);
        return jsonObject.getString("openid");
    }

    private String getAccessToken()
    {
        Map<String, String> map = new HashMap<>();
        map.put("grant_type", "client_credential");
        map.put("appid", WX_APP_ID);
        map.put("secret", WX_APP_SECRET);
        String json = HttpClientUtil.doGet(WX_ACCESS_TOKEN_URL, map);
        JSONObject jsonObject = JSON.parseObject(json);
        return jsonObject.getString("access_token");
    }

    private String getLocalNumber(String code, String accessToken)
    {
        String wxGetPhoneUrl = WX_GET_PHONE_NUMBER_URL + accessToken;
        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        String json = null;
        try {
            json = HttpClientUtil.doPost4Json(wxGetPhoneUrl, map);
        } catch (IOException e) {
            throw new GetPhoneWrongException(GET_PHONE_WRONG);
        }

        JSONObject jsonObject = JSON.parseObject(json);
        //传递过来的code不合法
        String errmsg = jsonObject.getString("errmsg");
        if(errmsg.contains("invalid code")) throw new GetPhoneWrongException(WX_GET_PHONE_CODE_INVALID);

        //调用微信接口获取手机号
        JSONObject phoneInfo = jsonObject.getJSONObject("phone_info"); // 获取嵌套的 "phone_info" 对象
        String phoneNumber = null;
        if (phoneInfo != null) {
            phoneNumber  = phoneInfo.getString("phoneNumber"); // 获取 "phone_info" 中的 "phoneNumber"
        } else {
            //获取手机号为空
            throw new GetPhoneWrongException(WX_PHONE_IS_WRONG);
        }
        return phoneNumber;
    }


}
